package main

import (
	"bytes"
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"

	"github.com/go-chi/chi"
	"github.com/go-chi/jwtauth"
	"golang.org/x/crypto/bcrypt"
)

func setupRouter() http.Handler {
	// Инициализация JWT-аутентификации
	tokenAuth = jwtauth.New("HS256", []byte("mysecretkey"), nil)

	r := chi.NewRouter()

	// Регистрация и вход
	r.Post("/api/register", registerHandler)
	r.Post("/api/login", loginHandler)

	// Защищенные маршруты
	r.Group(func(r chi.Router) {
		r.Use(jwtauth.Verifier(tokenAuth))
		r.Use(tokenVerifierMiddleware)
		r.Get("/api/protected", func(w http.ResponseWriter, r *http.Request) {
			w.WriteHeader(http.StatusOK)
			w.Write([]byte("Protected route accessed"))
		})
	})

	return r
}

func TestRegisterHandler(t *testing.T) {
	users = map[string]string{} // Очистка памяти перед каждым тестом

	router := setupRouter()
	user := User{Username: "testuser", Password: "password"}
	body, _ := json.Marshal(user)

	req, _ := http.NewRequest("POST", "/api/register", bytes.NewReader(body))
	rr := httptest.NewRecorder()
	router.ServeHTTP(rr, req)

	if status := rr.Code; status != http.StatusCreated {
		t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusCreated)
	}

	expected := `User testuser registered successfully`
	if rr.Body.String() != expected {
		t.Errorf("handler returned unexpected body: got %v want %v", rr.Body.String(), expected)
	}
}

func TestLoginHandler_Success(t *testing.T) {
	password, _ := bcrypt.GenerateFromPassword([]byte("password"), bcrypt.DefaultCost)
	users = map[string]string{"testuser": string(password)} // Добавление пользователя с хешированным паролем

	router := setupRouter()
	user := User{Username: "testuser", Password: "password"}
	body, _ := json.Marshal(user)

	req, _ := http.NewRequest("POST", "/api/login", bytes.NewReader(body))
	rr := httptest.NewRecorder()
	router.ServeHTTP(rr, req)

	if status := rr.Code; status != http.StatusOK {
		t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusOK)
	}

	// Проверка наличия токена в ответе
	var response map[string]string
	json.Unmarshal(rr.Body.Bytes(), &response)
	if _, ok := response["token"]; !ok {
		t.Errorf("handler did not return a token")
	}
}

func TestLoginHandler_InvalidJSON(t *testing.T) {
	router := setupRouter()
	invalidJSON := `{"Username": "testuser", "Password":`

	req, _ := http.NewRequest("POST", "/api/login", bytes.NewReader([]byte(invalidJSON)))
	rr := httptest.NewRecorder()
	router.ServeHTTP(rr, req)

	if status := rr.Code; status != http.StatusBadRequest {
		t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusBadRequest)
	}

}

func TestProtectedRoute_AccessWithInvalidToken(t *testing.T) {
	router := setupRouter()
	req, _ := http.NewRequest("GET", "/api/protected", nil)
	req.Header.Set("Authorization", "Bearer invalidtoken")
	rr := httptest.NewRecorder()
	router.ServeHTTP(rr, req)

	if status := rr.Code; status != http.StatusForbidden {
		t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusForbidden)
	}
}
func TestRegisterHandler_InvalidJSON(t *testing.T) {
	router := setupRouter()
	invalidJSON := `{"Username": "testuser", "Password":`

	req, _ := http.NewRequest("POST", "/api/register", bytes.NewReader([]byte(invalidJSON)))
	rr := httptest.NewRecorder()
	router.ServeHTTP(rr, req)

	if status := rr.Code; status != http.StatusBadRequest {
		t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusBadRequest)
	}

}

func TestTokenVerifierMiddleware_InvalidTokenFormat(t *testing.T) {
	router := setupRouter()
	req, _ := http.NewRequest("GET", "/api/protected", nil)
	req.Header.Set("Authorization", "Bearer invalidtoken")

	rr := httptest.NewRecorder()
	router.ServeHTTP(rr, req)

	if status := rr.Code; status != http.StatusForbidden {
		t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusForbidden)
	}

	expectedSubstring := "Forbidden"
	if !strings.Contains(rr.Body.String(), expectedSubstring) {
		t.Errorf("handler returned unexpected body: got %v want to contain %v", rr.Body.String(), expectedSubstring)
	}
}

func TestTokenVerifierMiddleware_NoToken(t *testing.T) {
	router := setupRouter()
	req, _ := http.NewRequest("GET", "/api/protected", nil)
	rr := httptest.NewRecorder()
	router.ServeHTTP(rr, req)

	if status := rr.Code; status != http.StatusForbidden {
		t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusForbidden)
	}

	expectedSubstring := "Forbidden"
	if !strings.Contains(rr.Body.String(), expectedSubstring) {
		t.Errorf("handler returned unexpected body: got %v want to contain %v", rr.Body.String(), expectedSubstring)
	}
}

func TestAddressSearchHandler(t *testing.T) {
	req, err := http.NewRequest(http.MethodGet, "/api/address/search", nil)
	if err != nil {
		t.Fatal(err)
	}

	rr := httptest.NewRecorder()
	handler := http.HandlerFunc(addressSearchHandler)
	handler.ServeHTTP(rr, req)

	if status := rr.Code; status != http.StatusOK {
		t.Errorf("handler returned wrong status code: got %v want %v",
			status, http.StatusOK)
	}

	expected := "Address search successful\n"
	if rr.Body.String() != expected {
		t.Errorf("handler returned unexpected body: got %v want %v",
			rr.Body.String(), expected)
	}
}

func TestAddressGeocodeHandler(t *testing.T) {
	req, err := http.NewRequest(http.MethodGet, "/api/address/geocode", nil)
	if err != nil {
		t.Fatal(err)
	}

	rr := httptest.NewRecorder()
	handler := http.HandlerFunc(addressGeocodeHandler)
	handler.ServeHTTP(rr, req)

	if status := rr.Code; status != http.StatusOK {
		t.Errorf("handler returned wrong status code: got %v want %v",
			status, http.StatusOK)
	}

	expected := "Geocoding successful\n"
	if rr.Body.String() != expected {
		t.Errorf("handler returned unexpected body: got %v want %v",
			rr.Body.String(), expected)
	}
}
